package com.open.auth.resp;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.provider.ClientDetails;

import com.alibaba.fastjson.JSON;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class OauthClientDetailsDTO implements ClientDetails, Serializable {

	private static final long serialVersionUID = 2559086700612464564L;

	private String clientId;

	private String resourceIds;

	private String clientSecret;

	private String scope;

	private String authorizedGrantTypes;

	private String registeredRedirectUris;

	private String authorities;

	private Integer accessTokenValiditySeconds;

	private Integer refreshTokenValiditySeconds;

	private String additionalInformation;

	private String autoApproveScopes;

	@Override
	public String getClientId() {
		return clientId;
	}

	public void setClientId(String clientId) {
		this.clientId = clientId;
	}

	@Override
	public String getClientSecret() {
		return clientSecret;
	}

	public void setClientSecret(String clientSecret) {
		this.clientSecret = clientSecret;
	}

	@Override
	public boolean isSecretRequired() {
		return StringUtils.isNotEmpty(clientSecret);
	}

	@Override
	public Set<String> getResourceIds() {
		if (StringUtils.isEmpty(resourceIds)) {
			return Collections.emptySet();
		}
		Set<String> resourceSet = new LinkedHashSet<>();
		String[] resources = resourceIds.trim().split(",");
		for (String resource : resources) {
			if (StringUtils.isEmpty(resource)) {
				continue;
			}
			resourceSet.add(resource.trim());
		}
		return resourceSet;
	}

	public void setResourceIds(String resourceIds) {
		this.resourceIds = resourceIds;
	}

	@Override
	public Set<String> getScope() {
		if (StringUtils.isEmpty(scope)) {
			return Collections.emptySet();
		}
		Set<String> scopeSet = new LinkedHashSet<>();
		String[] scopes = scope.trim().split(",");
		for (String scope : scopes) {
			if (StringUtils.isEmpty(scope)) {
				continue;
			}
			scopeSet.add(scope.trim());
		}
		return scopeSet;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}

	@Override
	public boolean isScoped() {
		return StringUtils.isNotEmpty(scope);
	}

	@Override
	public Set<String> getAuthorizedGrantTypes() {
		if (StringUtils.isEmpty(authorizedGrantTypes)) {
			return Collections.emptySet();
		}
		Set<String> authorizedGrantTypeSet = new LinkedHashSet<>();
		String[] types = authorizedGrantTypes.trim().split(",");
		for (String type : types) {
			if (StringUtils.isEmpty(type)) {
				continue;
			}
			authorizedGrantTypeSet.add(type.trim());
		}
		return authorizedGrantTypeSet;
	}

	public void setAuthorizedGrantTypes(String authorizedGrantTypes) {
		this.authorizedGrantTypes = authorizedGrantTypes;
	}

	@Override
	public Set<String> getRegisteredRedirectUri() {
		if (StringUtils.isEmpty(registeredRedirectUris)) {
			return Collections.emptySet();
		}
		Set<String> redirectUriSet = new LinkedHashSet<>();
		String[] uris = registeredRedirectUris.trim().split(",");
		for (String uri : uris) {
			if (StringUtils.isEmpty(uri)) {
				continue;
			}
			redirectUriSet.add(uri.trim());
		}
		return redirectUriSet;
	}

	public void setRegisteredRedirectUri(String registeredRedirectUris) {
		this.registeredRedirectUris = registeredRedirectUris;
	}

	@Override
	public Collection<GrantedAuthority> getAuthorities() {
		if (StringUtils.isEmpty(authorities)) {
			return Collections.emptyList();
		}
		List<GrantedAuthority> authorityList = new ArrayList<>();
		String[] authoritiesArray = authorities.trim().split(",");
		for (String authorities : authoritiesArray) {
			if (StringUtils.isEmpty(authorities)) {
				continue;
			}
			authorityList.add((GrantedAuthority) () -> authorities.trim());
		}
		return authorityList;
	}

	public void setAuthorities(String authorities) {
		this.authorities = authorities;
	}

	@Override
	public Integer getAccessTokenValiditySeconds() {
		return accessTokenValiditySeconds;
	}

	public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) {
		this.accessTokenValiditySeconds = accessTokenValiditySeconds;
	}

	@Override
	public Integer getRefreshTokenValiditySeconds() {
		return refreshTokenValiditySeconds;
	}

	public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) {
		this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
	}

	@Override
	public Map<String, Object> getAdditionalInformation() {
		if (StringUtils.isEmpty(additionalInformation)) {
			return Collections.emptyMap();
		}
		return JSON.parseObject(additionalInformation);
	}

	public void setAdditionalInformation(String additionalInformation) {
		this.additionalInformation = additionalInformation;
	}

	public Set<String> getAutoApproveScopes() {
		if (StringUtils.isEmpty(autoApproveScopes)) {
			return Collections.emptySet();
		}
		Set<String> approveSet = new HashSet<>();
		String[] approves = autoApproveScopes.trim().split(",");
		for (String approve : approves) {
			if (StringUtils.isEmpty(approve)) {
				continue;
			}
			approveSet.add(approve.trim());
		}
		return approveSet;
	}

	public void setAutoApproveScopes(String autoApproveScopes) {
		this.autoApproveScopes = autoApproveScopes;
	}

	@Override
	public boolean isAutoApprove(String scope) {
		if (CollectionUtils.isEmpty(getAutoApproveScopes())) {
			return false;
		} else {
			Iterator<String> iter = getAutoApproveScopes().iterator();
			String auto;
			do {
				if (!iter.hasNext()) {
					return false;
				}
				auto = (String) iter.next();
			} while (!auto.equals("true") && !scope.matches(auto));
			return true;
		}
	}

}
